package cn.bugstack.mybatis.type;

/**
 * @author wcc
 * @description 类型处理器注册机
 * @create
 */

import java.lang.reflect.Type;
import java.util.Date;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;

/**
 * @author wcc
 * @description 类型处理注册机
 * @create
 */

public class TypeHandlerRegistry {
    private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<>(JdbcType.class);
    //一个Java类型对应不止一个jdbc类型 每个jdbc类型都有对应的typeHandler
    // key:String  value:{{key:varchar, value:StringHandler}, {key:char, value:StringHandler}}
    private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<>();
    private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLERS_MAP = new HashMap<>();
    public TypeHandlerRegistry(){
        register(Long.class, new LongTypeHandler());
        register(long.class, new LongTypeHandler());
        register(String.class,new StringTypeHandler());
        register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
        register(String.class, JdbcType.CHAR, new StringTypeHandler());
        register(Date.class, new DateTypeHandler());
    }
    private void register(Type javaType,  TypeHandler<?> typeHandler){
        register(javaType, null, typeHandler);
    }
    private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> typeHandler){
        if (null != javaType){
            Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.computeIfAbsent(javaType, k -> new HashMap<>());
            map.put(jdbcType, typeHandler);
        }
        ALL_TYPE_HANDLERS_MAP.put(typeHandler.getClass(), typeHandler);
    }
    public void register(JdbcType jdbcType, TypeHandler<?> handler) {
        JDBC_TYPE_HANDLER_MAP.put(jdbcType, handler);
    }

    public <T> TypeHandler<T> getTypeHandler(Class<T> javaType, JdbcType jdbcType){
        return getTypeHandler((Type) javaType, jdbcType);
    }

    public <T> TypeHandler<T> getTypeHandler(Type javaType, JdbcType jdbcType){
        Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = TYPE_HANDLER_MAP.get(javaType);
        TypeHandler<?> handler = null;
        if (jdbcHandlerMap != null){
            handler = jdbcHandlerMap.get(jdbcType);
            if (handler == null)
                handler = jdbcHandlerMap.get(null);
        }
        return (TypeHandler<T>) handler;
    }
    public boolean hasTypeHandler(Class<?> type){
        return hasTypeHandler(type, null);
    }
    public boolean hasTypeHandler(Class<?> javaType, JdbcType jdbcType) {
        return javaType != null && getTypeHandler((Type) javaType, jdbcType) != null;
    }

    public TypeHandler<?> getMappingTypehandler(Class<? extends TypeHandler<?>> typeHandlerType) {
        return ALL_TYPE_HANDLERS_MAP.get(typeHandlerType);
    }
}
